﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup;
using Avalon.Windows.Controls;
using AvalonDock;
using Csla;
using Csla.Core;
using Csla.OpenExpressApp;
using Csla.Wpf;
using log4net;
using OpenExpressApp.Command;
using OpenExpressApp.MetaAttribute;
using OpenExpressApp.MetaModel;
using OpenExpressApp.Module;
using OpenExpressApp.Module.WPF;
using OpenExpressApp.Module.WPF.Editors;
using OpenExpressApp.Template;
using OpenExpressApp.Types;
using OpenExpressApp.WPF.Controls;
using OpenExpressApp.WPF.Templete;
using Ricciolo.Controls;
using OpenExpressApp.MetaModel.Command;

namespace OpenExpressApp.WPF.Command
{
    [Command(CommandNames.CopyAndNew, Label = "复制添加", ImageName = "CopyAndAdd.bmp", ToolTip = "复制添加")]
    public class CopyAndNewCommand : WPFListViewCommand
    {
        public override bool CanExecute(ListObjectView view)
        {
            if (base.CanExecute(view) == false)
            {
                return false;
            }
            if (this.SelectedRightType(view) == false)
            {
                return false;
            }
            var bindingList = view.Data as IBindingList;
            if (bindingList == null || bindingList.AllowNew == false)
            {
                return false;
            }
            return true;
        }

        public override void Execute(ListObjectView view)
        {
            InnerCopyAndNewCommand innerCommand = new InnerCopyAndNewCommand();
            innerCommand.Execute(view);
        }

        #region InnerCopyAndNewCommand

        /// <summary>
        /// CopyAndNewCommand类的实现必须是无状态的。
        /// 但是由于这里要存储状态，所以申明了这个私有类。
        /// </summary>
        private class InnerCopyAndNewCommand
        {
            private ListObjectView _currentView;

            private bool? _isDealingTree;

            /// <summary>
            /// 是否在处理树
            /// </summary>
            private bool IsDealingTree
            {
                get
                {
                    if (this._isDealingTree.HasValue == false)
                    {
                        if (this._currentView == null)
                        {
                            return false;
                        }

                        this._isDealingTree = this._currentView.Data is IOrderedObjectCollection;
                    }
                    return this._isDealingTree.Value;
                }
            }

            public void Execute(ListObjectView view)
            {
                this._currentView = view;

                this.InnerExecute();

                this._currentView = null;
            }

            private void InnerExecute()
            {
                var currentObject = this._currentView.CurrentObject as BusinessBase;
                var bindingList = this._currentView.Data as IBindingList;

                var listener = currentObject as ICopySource;
                if (listener != null)
                {
                    listener.NotifyCopying();
                }

                //拷贝一个新的对象
                BusinessBase newObject = this.CopyObject(currentObject, null, true);

                //如果是根节点,则重新装载树
                if (this.IsDealingTree && (newObject as ITreeNode).Pid == null)
                {
                    var treeView = this._currentView.Control as MultiObjectTreeView;
                    treeView.BindData(null);
                }

                this._currentView.CurrentObject = newObject;
            }

            /// <summary>
            /// 复制一个指定的对象
            /// 包括所有的孩子（如果是树节点的话），所有的实体属性和细表属性。
            /// </summary>
            /// <param name="oldObject">需要复制的对象</param>
            /// <param name="parentNode">如果不为null，表示需要设置新的对象成为这个对象的孩子</param>
            /// <param name="modifyName">是否在这个对象的Name属性上添加“-新增”</param>
            /// <returns></returns>
            private BusinessBase CopyObject(BusinessBase oldObject, ITreeNode parentNode, bool modifyName)
            {
                var oldNode = oldObject as ITreeNode;

                //添加一个新的空对象
                BusinessBase newObject = null;
                if (parentNode != null)
                {
                    newObject = this.NewObject(parentNode as BusinessBase, true);
                }
                else
                {
                    newObject = this.NewObject(oldObject, false);
                }

                MethodInfo beforeCopy = newObject.GetType().GetMethod("BeforeCopy");
                if (beforeCopy != null)
                {
                    beforeCopy.Invoke(newObject, null);
                }

                try
                {
                    var newNode = newObject as ITreeNode;

                    //属性拷贝
                    this.CopyProperties(newObject, oldObject);

                    #region 如果是树，再把所有的孩子都拷贝

                    if (this.IsDealingTree)
                    {
                        //打开控件的这个节点
                        var treeView = this._currentView.Control as MultiObjectTreeView;
                        treeView.Expand(oldObject);

                        //拷贝所有的孩子
                        var children = oldNode.ChildrenNodes;
                        for (int i = 0, c = children.Count; i < c; i++)
                        {
                            var oldChild = children[i] as BusinessBase;
                            //复制一个新的节点作为newObject的孩子
                            var newChild = this.CopyObject(oldChild, newNode, false);
                        }
                    }

                    #endregion

                    this.ModifyName(newObject, modifyName);
                }
                finally
                {
                    MethodInfo afterCopy = newObject.GetType().GetMethod("AfterCopy");
                    if (afterCopy != null)
                    {
                        afterCopy.Invoke(newObject, null);
                    }
                }

                return newObject;
            }

            /// <summary>
            /// 构造一个新的对象
            /// 
            /// 如果是在处理树：
            /// 在currentObject的同级最后 或者 作为currentObject的孩子最后，添加这个新的对象
            /// </summary>
            /// <param name="currentObject">作为位置目标的对象</param>
            /// <param name="newAsChild">如果是树的节点，表示是否添加的对象是currentObject的孩子节点</param>
            /// <returns></returns>
            private BusinessBase NewObject(BusinessBase currentObject, bool newAsChild)
            {
                if (currentObject == null) throw new ArgumentNullException("targetObject");

                var currentNode = currentObject as ITreeNode;
                var bindingList = this._currentView.Data as IBindingList;
                var treeList = bindingList as IOrderedTreeNodeCollection;

                //是否已经选择了一个非根的树节点
                bool selectedChildNode = currentNode != null && currentNode.ParentNode != null;

                BusinessBase newObject = null;

                #region 构造新的对象

                if (this.IsDealingTree)
                {
                    if (newAsChild)
                    {
                        newObject = treeList.CreateNode(currentNode, true, false) as BusinessBase;
                    }
                    else
                    {
                        #region 同层添加

                        //新节点应该加在这一层节点的最后
                        IList<ITreeNode> nodeOfALayer = null;

                        //下面的操作会使用到关系。
                        treeList.EnsureObjectRelations();

                        //如果选择了一个非根的节点
                        if (selectedChildNode)
                        {
                            nodeOfALayer = currentNode.ParentNode.ChildrenNodes;
                        }
                        else
                        {
                            if (treeList.Count > 0)
                            {
                                //加到最后一个根节点之后
                                nodeOfALayer = treeList.FindRoots();
                            }
                        }

                        if (nodeOfALayer != null && nodeOfALayer.Count > 0)
                        {
                            var targetNode = nodeOfALayer[nodeOfALayer.Count - 1];
                            newObject = treeList.CreateNode(targetNode, false, false) as BusinessBase;
                        }

                        #endregion
                    }
                }

                //没有找到节点作为位置的目标，直接加到链表的最后。
                if (newObject == null)
                {
                    newObject = bindingList.AddNew() as BusinessBase;
                }

                #endregion

                AddCommand.InitProperties(newObject, this._currentView);

                return newObject;
            }

            /// <summary>
            /// 拷贝除了OrderNo以外的对象的属性值
            /// </summary>
            /// <param name="newObject"></param>
            /// <param name="oldObject"></param>
            private void CopyProperties(BusinessBase newObject, BusinessBase oldObject)
            {
                if (newObject == null) throw new ArgumentNullException("newObject");
                if (oldObject == null) throw new ArgumentNullException("oldObject");

                //这个值不能在复制的过程中丢失
                //暂存ParentNode
                var newNode = newObject as ITreeNode;
                ITreeNode cachedParent = null;
                if (this.IsDealingTree)
                {
                    cachedParent = newNode.ParentNode;
                }
                //暂存OrderNo
                var orderedObject = newObject as IOrderedObject;
                int oldOrderNo = 0;
                if (orderedObject != null)
                {
                    oldOrderNo = orderedObject.OrderNo;
                }

                #region 拷贝所有属性值

                //如果对象实现了AssignFrom，则使用对象自己的AssignFrom，否则根据规则自动赋值
                MethodInfo assignFrom = newObject.GetType().GetMethod("PasterAndSave");
                if (null != assignFrom)
                {
                    assignFrom.Invoke(newObject, new object[] { oldObject });
                    ((this._currentView.Control as FrameworkElement).GetFrameTemplate().Controller as IListDetailFrameController).AsyncGetCurObject(true);
                }
                else
                {
                    //拷贝值
                    newObject.AssignFrom(oldObject);
                }

                #endregion

                //还原OrderNo
                if (orderedObject != null)
                {
                    orderedObject.OrderNo = oldOrderNo;
                }
                //还原ParentNode
                if (this.IsDealingTree)
                {
                    newNode.ParentNode = cachedParent;
                }
            }

            /// <summary>
            /// 有必要的话，就修改Name
            /// </summary>
            /// <param name="newObject"></param>
            private void ModifyName(BusinessBase newObject, bool modifyName)
            {
                if (modifyName && newObject.GetType().GetProperty("Name") != null)
                {
                    newObject.SetPropertyValue("Name", newObject.GetPropertyValue("Name") + "-新增");
                }
            }


            //Debug 用。
            //private void ListenSelfDirtyChange(BusinessBase src)
            //{
            //    src.IsSelfDirtyChanged += new EventHandler(obj_IsSelfDirtyChanged);

            //    BusinessObjectInfo boInfo = ApplicationModel.GetBusinessObjectInfo(src.GetType());

            //    foreach (BusinessObjectsPropertyInfo propInfo in boInfo.BOsPropertyInfos)
            //    {
            //        if (propInfo.NotCopy)
            //        {
            //            continue;
            //        }

            //        var srcList = src.GetPropertyValue(propInfo.Name) as IList;
            //        foreach (BusinessBase oldItem in srcList)
            //        {
            //            ListenSelfDirtyChange(oldItem);
            //        }
            //    }
            //}

            //void obj_IsSelfDirtyChanged(object sender, EventArgs e)
            //{

            //}
        }

        #endregion
    }
}
